package com.laogao.web;

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.concurrent.Semaphore;
import java.util.concurrent.TimeUnit;

/**
 * 使用 Semaphore(计数信号量) 实现限流功能
 * 限制同一时刻对某个 API 的并发请求数，防止过多的请求导致服务器过载。
 * <b>description</b>： Java进阶、性能优化实战案例100讲,
 * 微信公众号:程序员恰恰，源码 & 文档 & 技术支持，请加个人微信号：it3306 <br>
 * <b>time</b>：2025/2/20 21:01 <br>
 * <b>author</b>：ready lao_gao
 */
@RestController
public class TestController {

    /**
     * Juc中的Semaphore(计数信号量)可以实现限流功能，可以将 Semaphore 想象成停车场入口的大爷，
     * 大爷手里面拥有一定数量的停车卡（也可以说是令牌），卡的数量是多少呢？就是Semaphore构造方法中指定的，如下就是50个卡，
     * 车主想进去停车，先要从大爷手中拿到一张卡，出来的时候，需要还给大爷，如果拿不到卡，就不能进去停车。
     * semaphore 内部提供了获取令牌，和还令牌的一些方法
     */

    /**
     * 基本思路：
     * 设定一个最大并发数（即允许同时进行的请求数）。
     * 线程尝试获取信号量，如果可以获取到信号量，则执行操作。
     * 如果信号量已被其他线程占用，且在规定的时间内无法获取到信号量，则拒绝请求或者延迟处理。
     * <p>
     * 来个案例:
     * 下面是一个下单的方法，这个方法最多只允许 50 个并发，若超过50个并发，则进来的请求，最多等待1秒，如果无法获取到令牌，则快速返回失败，请重试
     */

    //初始化了一个信号量，表示最多允许 50 个线程同时访问资源。
    private Semaphore semaphore = new Semaphore(50);

    @GetMapping("/placeOrder")
    public String placeOrder() throws InterruptedException {

        /**
         * 下面的代码，尝试在最多等待 1 秒的时间内获取 1 个信号量。如果在 1 秒内成功获取到了信号量，获取成功，则进入下单逻辑，获取失败，则返回系统繁忙，请稍后重试
         * semaphore 在上面定义的，里面有50个令牌，也就是同时可以支持50个并发请求
         * 参数:
         * permits: 请求的信号量数量。在这个例子中是 1，表示请求一个信号量。
         * timeout: 最大等待时间，即在获取信号量时的最大等待时长。在这个例子中是 1L，表示等待 1 秒。
         * unit: 时间单位。TimeUnit.SECONDS 表示时间单位为秒，意味着等待 1 秒。
         * 返回值:
         * true: 表示成功获取了信号量。
         * false: 表示在指定时间内没有获取到信号量。
         */
        boolean flag = this.semaphore.tryAcquire(1, 1L, TimeUnit.SECONDS);
        // 获取到令牌，则进入下单逻辑
        if (flag) {
            try {
                //这里休眠2秒，模拟下单的操作
                TimeUnit.SECONDS.sleep(2);
                return "下单成功";
            } finally {
                //这里一定不要漏掉了，令牌用完了，要还回去
                this.semaphore.release();
            }
        } else {
            return "系统繁忙，请稍后重试";
        }
    }
}
